package com.luo.sc.oidc.authserver.handler.login;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 通用登录 - 用户详细信息
 *
 * @author luohq
 * @version 1.0.0
 * @date 2022-03-03 15:19
 */
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@JsonIgnoreProperties({"accountNonExpired", "accountNonLocked", "credentialsNonExpired", "enabled"})
public class UniLoginUserDetails implements UserDetails {

    /**
     * 用户账户
     */
    private String username;
    /**
     * 用户密码
     */
    private String password;
    /**
     * 用户相关属性
     */
    private Map<String, Object> attrs;
    /**
     * 用户权限
     */
    private Collection<? extends GrantedAuthority> authorities;

    public UniLoginUserDetails() {
    }

    public UniLoginUserDetails(String username, String password, Collection<? extends GrantedAuthority> authorities, Map<String, Object> attrs) {
        Assert.hasText(username, "Username must not be empty! Username represents user's unique identity!");
        this.username = username;
        this.password = password;
        this.authorities = authorities;
        this.attrs = attrs;
    }

    private UniLoginUserDetails(Builder builder) {
        username = builder.username;
        password = builder.password;
        setAttrs(builder.attrs);
        authorities = builder.authorities;
    }

    public static Builder builder() {
        return new Builder();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.authorities;
    }


    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return this.username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return false;
    }

    @Override
    public boolean isEnabled() {
        return false;
    }

    public Map<String, Object> getAttrs() {
        return attrs;
    }

    public void setAttrs(Map<String, Object> attrs) {
        this.attrs = attrs;
    }

    public <T> T getAttr(String attrName) {
        return (T) Optional.ofNullable(this.attrs)
                .map(attrs -> attrs.get(attrName))
                .orElse(null);
    }

    public void setAttr(String attrName, Object attrVal) {
        Optional.ofNullable(this.attrs)
                .ifPresent(attr -> attr.put(attrName, attrVal));
    }


    public static final class Builder {
        private String username;
        private String password;
        private Map<String, Object> attrs;
        private Collection<? extends GrantedAuthority> authorities;

        private Builder() {
        }

        public Builder username(String val) {
            username = val;
            return this;
        }

        public Builder password(String val) {
            password = val;
            return this;
        }

        public Builder attrs(Map<String, Object> val) {
            attrs = val;
            return this;
        }

        public Builder authorities(Collection<? extends GrantedAuthority> val) {
            authorities = val;
            return this;
        }

        public Builder authorities(Set<String> val) {
            authorities = val.stream()
                    .map(SimpleGrantedAuthority::new)
                    .collect(Collectors.toSet());
            return this;
        }

        public Builder authorities(List<String> val) {
            authorities = val.stream()
                    .map(SimpleGrantedAuthority::new)
                    .collect(Collectors.toSet());
            return this;
        }

        public Builder attr(String attrName, Object attrVal) {
            if (null == this.attrs) {
                this.attrs = new HashMap<>(16);
            }
            this.attrs.put(attrName, attrVal);
            return this;
        }

        public UniLoginUserDetails build() {
            return new UniLoginUserDetails(this);
        }
    }
}
